package com.sumainfor.wx.tenant.service.impl;

import com.sumainfor.common.Constants;
import com.sumainfor.common.config.RedisUtils;
import com.sumainfor.common.exception.TCException;
import com.sumainfor.common.util.FieldCheckUtil;
import com.sumainfor.common.util.JsonResult;
import com.sumainfor.common.utlis.AuthUtil;
import com.sumainfor.common.utlis.ComUtils;
import com.sumainfor.common.utlis.ParamsCommon;
import com.sumainfor.common.wechat.WeChatConfig;
import com.sumainfor.wx.tenant.dao.TctenTenantMiddleMapper;
import com.sumainfor.wx.tenant.dao.UtilsMapper;
import com.sumainfor.wx.tenant.dao.WechatMapper;
import com.sumainfor.wx.tenant.feign.DevelopmentFeignClient;
import com.sumainfor.wx.tenant.feign.MarketFeignClient;
import com.sumainfor.wx.tenant.service.WechatService;
import com.sumainfor.wx.tenant.util.HttpUtil;
import com.sumainfor.wx.tenant.util.WeChartUtil;
import com.vdurmont.emoji.EmojiParser;
import lombok.Builder;
import net.sf.json.JSONObject;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 微信授权登录类
 */
@Service
public class WechatServiceimpl implements WechatService {

    private ReentrantLock lock = new ReentrantLock(false);
    Logger log = LoggerFactory.getLogger(WechatServiceimpl.class);

    @Autowired
    WechatMapper wxdao;

    @Autowired
    MarketFeignClient marketFeignClient;

    @Autowired
    DevelopmentFeignClient developmentFeignClient;

    @Autowired
    private UtilsMapper utilsMapper;
    String UUID2 = null;
    @Autowired
    private TctenTenantMiddleMapper tctenTenantMiddleMapper;

    @Autowired
    private RedisUtils redis;

    /**
     * 判断该openID是否绑定用户资料，如果绑定更新用户微信资料，如果未绑定返回微信资料给前端
     *
     * @author xiaoma
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Map<String, Object> isBind(Map<String, Object> params) throws Exception {
        Map<String, Object> result = new HashMap<String, Object>();
        /**
         * 加锁操作
         */
        lock.lock();
        try {
            String code = params.get("code").toString();//首先获取code
            String url = "https://api.weixin.qq.com/sns/oauth2/access_token?"
                    + "appid=" + WeChatConfig.APP_ID
                    + "&secret=" + WeChatConfig.APP_SECRET
                    + "&code=" + code
                    + "&grant_type=authorization_code";
            JSONObject jsonObject = AuthUtil.doGetJson(url);
            log.info("jsonObject---》" + jsonObject);//微信token
            String openid = jsonObject.getString("openid");//拿到用户的opid
            String token = jsonObject.getString("access_token");//拿到微信生成的access_token 两小时刷新一次
            //再次请求微信
            String infoUrl = "https://api.weixin.qq.com/sns/userinfo?"
                    + "access_token=" + token
                    + "&openid=" + openid
                    + "&lang=zh_CN";
            JSONObject infoUrls = AuthUtil.doGetJson(infoUrl);
            log.info("infoUrls---》" + infoUrls);//拿到用户的基本的信息


            //请求拿到koten 注意 这个生成的token 需要在微信公众平台上面设置服务器ip的白名单不然微信会报一个	调用接口的IP地址不在白名单中，请在接口IP白名单中进行设置。（小程序及小游戏调用不要求IP地址在白名单内。）
            String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?"
                    + "appid=" + WeChatConfig.APP_ID
                    + "&secret=" + WeChatConfig.APP_SECRET
                    + "&grant_type=client_credential";
            JSONObject tokenUrls = AuthUtil.doGetJson(tokenUrl);
            log.info("--------------------------------------------");//拿到用户的基本的信息
            log.info("--------------------------------------------");//拿到用户的基本的信息
            log.info("tokenUrls---》" + tokenUrls);//拿到用户的基本的信息
            log.info("--------------------------------------------");//拿到用户的基本的信息
            log.info("--------------------------------------------");//拿到用户的基本的信息
            log.info("--------------------------------------------");//拿到用户的基本的信息

            String tokens = tokenUrls.getString("access_token");

            //再次请求微信接口获取是否关注了微信公众号
            String subscribeUrl = "https://api.weixin.qq.com/cgi-bin/user/info?"
                    + "access_token=" + tokens
                    + "&openid=" + openid
                    + "&lang=zh_CN";
            JSONObject subscribeUrls = AuthUtil.doGetJson(subscribeUrl);
            log.info("--------------------------------------------");//拿到用户的基本的信息
            log.info("--------------------------------------------");//拿到用户的基本的信息
            log.info("--------------------------------------------");//拿到用户的基本的信息
            log.info("获得是否关注公众号subscribeUrls---》" + subscribeUrls);//拿到用户的基本的信息
            log.info("--------------------------------------------");//拿到用户的基本的信息
            log.info("--------------------------------------------");//拿到用户的基本的信息
            log.info("--------------------------------------------");//拿到用户的基本的信息


            Map<String, Object> is = new HashMap<String, Object>();
            is.put("uopid", openid);//用户的id
            is.put("unionid", infoUrls.get("unionid"));//用户的id 平台unionid
            is.put("sex", infoUrls.get("sex"));//性别
            is.put("uimg", infoUrls.get("headimgurl"));//头像
            is.put("unknm", infoUrls.get("nickname"));////名称
            is.put("country", infoUrls.get("country"));
            is.put("province", infoUrls.get("province"));
            is.put("city", infoUrls.get("city"));
            is.put("subscribe", subscribeUrls.get("subscribe"));//是否关注
            int isUopid = wxdao.isUopid(is);//查询是否有opid
            Map<String, Object> user = wxdao.getUser(is);//查询是否有opid  TenId租客id
            //判断该openID是否绑定了用户
            if (isUopid > 0) {//说明绑定了用户资料
                is.put("nknm", infoUrls.get("nickname"));
                is.put("term", "1");// 创建端 Insert端： 1 用户端 2 PC端 3 待定
                is.put("fnc",
                        this.getClass().getSimpleName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName());// 创建Function名
                ParamsCommon.commonUpdateParms(is);
                try {
                    //  wxdao.updateUsr(is);//更新usr表中微信资料
                    wxdao.updateWechat(is);//更新用户微信资料表
                    result.put("isBind", 1);//返回已经绑定标识，更新该用户的微信基本资料
                    result.put("TenId", user.get("TenId"));
                    result.put("uopid", openid);
                } catch (Exception e) {
                    e.printStackTrace();
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//事物回滚
                    result.put("isBind", 0);//返回已经绑定标识，更新该用户的微信基本资料
                    result.put("msg", "服务器繁忙...");
                }
            } else {
                is.put("term", "1");// 创建端 Insert端： 1 用户端 2 PC端 3 待定
                is.put("fnc",
                        this.getClass().getSimpleName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName());// 创建Function名
                ParamsCommon.commonInsertParms(is);
                try {
                    Map<String, Object> wxusr = new HashMap<String, Object>();
                    wxusr.put("openid", openid);
                    Map<String, Object> wxusrs = wxdao.getUserWx(wxusr);//根据openID获取用户资料
                    log.info("wxusrs---" + wxusrs);
                    if (wxusrs == null) {//判断是否为空
                        wxdao.addUserWx(is);//更新用户微信资料表
                    }
                    result.put("isBind", 0);//返回未绑定标识，并且返回对应的微信用户资料
                    result.put("uopid", openid);
                    log.info("result----》》" + result);
                } catch (Exception e) {
                    e.printStackTrace();
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//事物回滚
                    result.put("isBind", 0);//返回已经绑定标识，更新该用户的微信基本资料
                    result.put("msg", "服务器繁忙...");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//事物回滚
            result.put("isBind", 0);//返回已经绑定标识，更新该用户的微信基本资料
            result.put("msg", "服务器繁忙...");
        } finally {
            lock.unlock();
        }
        return result;
    }

    /**
     * 获得Token
     *
     * @return
     */
    @Override
    public JsonResult getLocalToken(String url) {
        String uuid = UUID.randomUUID().toString().replace("-", "");
        //jssdk权限验证参数
        TreeMap<Object, Object> map = new TreeMap<>();
        map.put("appId", WeChatConfig.APP_ID);
        long timestamp = System.currentTimeMillis();
        map.put("timestamp", timestamp);
        map.put("signature", getSignature(timestamp, uuid, url));
        map.put("nonceStr", uuid);
        return JsonResult.success(map);
    }

    private String getSignature(Long timestamp, String noncestr, String url) {
        //对所有待签名参数按照字段名的ASCII 码从小到大排序（字典序）
        Map<String, Object> map = new TreeMap<>();
        map.put("jsapi_ticket", getJsapi_ticket());
        map.put("timestamp", timestamp);
        map.put("noncestr", noncestr);
        map.put("url", url);
        //使用URL键值对的格式（即key1=value1&key2=value2…）拼接成字符串string1
        StringBuilder sb = new StringBuilder();
        Set<String> set = map.keySet();
        for (String key : set) {
            sb.append(key + "=" + map.get(key)).append("&");
        }
        //去掉最后一个&符号
        String temp = sb.substring(0, sb.length() - 1);
        //使用sha1加密
        return DigestUtils.sha1Hex(temp);
    }

    /**
     * 获取JSSDK的jsapi_ticket
     */
    public String getJsapi_ticket() {
        //发起请求到指定的接口
        String result = null;
        try {
            result = HttpUtil.getBody(WeChatConfig.GET_TICKET_URL.replace("ACCESS_TOKEN", WeChartUtil.getAccessToken()));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 发送验证码的时候验证一下手机号码是否被绑定
     *
     * @param params
     * @return
     */
    @Override
    public Integer getCountPhone(Map<String, Object> params) {
        return wxdao.getCountPhone(params);
    }

    @Override
    public Integer getCountPhone1(Map<String, Object> params) {
        return wxdao.getCountPhone1(params);
    }

    /**
     * 用户通过手机验证码验证之后填写密码进行注册
     *
     * @param params
     * @return
     * @author xiaoma
     */
    @Override
    public Map<String, Object> addusr(Map<String, Object> params) {
        Map<String, Object> result = new HashMap<String, Object>();
        log.info("params=====>" + params);
        /**
         * 加锁操作
         */
        lock.lock();
        try {
            //查询是否注册了
            if (wxdao.getCountUsrByOpid(params) > 0) {
                result.put("isBind", 0);//返回已经绑定标识，更新该用户的微信基本资料
                result.put("msg", "该用户已注册");
                result.put("errorcode", 400);
            } else {
                //查询该手机号是否在后台创建工单的时候录入过
                log.info("手机号:" + params.get("phone"));
                params.put("Phone", params.get("phone"));
                Map<String, Object> tamktMap = tctenTenantMiddleMapper.getTctenTenantMiddle(params);
                log.info("tamktMap:" + tamktMap);
                if (tamktMap != null) {
                    UUID2 = tamktMap.get("SysId").toString();
                } else {//如果在和pc的关联表中根据手机号查询不到记录，就取新增一条关联记录
                    //租客编号
                    tamktMap = new HashMap<String, Object>();
                    Map<String, Object> uuid = utilsMapper.getUUID(new HashMap<String, Object>() {{
                        put("uuid", "SysId");
                        put("database", Constants.DATA_SOURCE_TCTEN);
                        put("surface", "tcten_tenant_middle");
                    }});
                    log.info("uuid：" + uuid);
                    if (uuid != null && (!uuid.get("uuid").toString().equals(""))) {
                        int number = Integer.valueOf(uuid.get("uuid").toString());
                        UUID2 = ComUtils.getLocalTrmSeqNum("ti", number);
                    } else {
                        UUID2 = ComUtils.getLocalTrmSeqNum("ti", 0);
                    }
                    log.info("UUID2" + UUID2);
                    tamktMap.put("SysId", UUID2);
                    tamktMap.put("Phone", params.get("phone"));
                    tamktMap.put("term", "1");// 创建端 Insert端： 1 租客端 2市场部 3 工程部   4运营部   5财务部  6总经办 7发展部
                    tamktMap.put("fnc",
                            this.getClass().getSimpleName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName());// 创建Function名
                    ParamsCommon.commonInsertParms(tamktMap);
                    Integer count = tctenTenantMiddleMapper.addTctenTenantMiddle(tamktMap);
                    if (count == null || count == 0) {
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//事物回滚
                        result.put("errorcode", 500);
                        result.put("msg", "PC关联新增失败");
                    }
                }
                params.put("openid", params.get("uopid"));
                // String password =params.get("loginpad").toString();
                // params.put("loginpad", MD5.encode(password));//MD5加密一次
                Map<String, Object> wxusrs = wxdao.getUserWx(params);//首先通过opid 查询出微信绑定的信息
                //headimgurl,nickname,sex
                params.put("TenImg", wxusrs.get("headimgurl"));//微信头像
                params.put("TenName", EmojiParser.parseToHtmlDecimal((String) wxusrs.get("nickname")));//微信名称
                params.put("TenSex", wxusrs.get("sex"));//微信里面认证的性别
                params.put("TenId", UUID2);//生成uuid;
                params.put("term", "1");// 创建端 Insert端： 1 用户端 2 PC端 3 待定
                params.put("fnc",
                        this.getClass().getSimpleName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName());// 创建Function名
                ParamsCommon.commonInsertParms(params);


                Map<String, Object> instmMap = new HashMap<>();
                instmMap.put("phone", params.get("phone"));
                if (wxdao.addUser(params) != 0) {


                    Map<String, Object> getInstmByPhoneMap = wxdao.getInstmByPhone(instmMap);
                    //修改别人的接口
                    //获取创建时间>注册时间的
                    JsonResult mesres = developmentFeignClient.getMesId(getInstmByPhoneMap);//首先先获取系统消息id


                    List<Map<String, Object>> mrslist = (List<Map<String, Object>>) mesres.get("result");

                    if (mrslist.size() != 0) {
                        for (Map<String, Object> msmap : mrslist) {//
                            Map<String, Object> syamap = new HashMap<String, Object>();
                            syamap.put("TenId", UUID2);
                            syamap.put("Sysid", msmap.get("MesId"));
                            syamap.put("term", "1");// 创建端 Insert端： 1 用户端 2 PC端 3 待定
                            syamap.put("fnc",
                                    this.getClass().getSimpleName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName());// 创建Function名
                            ParamsCommon.commonInsertParms(syamap);
                            wxdao.saveSysmsg(syamap);//新增系统消息
                        }


                    }

                    result.put("isBind", 1);//返回已经绑定标识，更新该用户的微信基本资料
                    result.put("TenId", UUID2);
                    result.put("uopid", params.get("uopid"));
                    result.put("errorcode", 0);
                    wxdao.updateWechat(params);//微信绑定usrid
                    redis.delete(params.get("phone").toString());//验证成功了之后删除redis中的key
                } else {
                    result.put("isBind", 0);//返回已经绑定标识，更新该用户的微信基本资料
                    result.put("msg", "操作失败");
                    result.put("errorcode", 400);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//事物回滚
            result.put("isBind", 0);//返回已经绑定标识，更新该用户的微信基本资料
            result.put("msg", "服务器繁忙...");
        } finally {
            lock.unlock();
        }
        return result;
    }

    /**
     * 根据TenId和openid 查询个人信息
     *
     * @param params
     * @return
     */
    @Override
    public Map<String, Object> getUsr(Map<String, Object> params) {
        if (!FieldCheckUtil.isMapFieldNotNull(params, "TenId", "uopid")) {
            throw new TCException("参数不完整");
        }
        Map<String, Object> getUsr = wxdao.getUsr(params);
        JsonResult<Map<String, Object>> para = marketFeignClient.selectPaymentAndPact(params);

        Map<String, Object> par = (Map<String, Object>) para.getResult();
        getUsr.put("ispayment", par.get("Payment"));
        getUsr.put("ispactcount", par.get("pactCount"));
        getUsr.put("isauthen", wxdao.getCountusrinfor(params));//查询是否实名认证
        getUsr.put("ismsg", wxdao.countSysMsgById(params));//查询是否有系统消息
//        Map<String,Object>getSigningWechatOwner=(Map<String,Object>)marketFeignClient.getSigningWechatOwner(params).getResult();
//        //查询当前用户是否成为了业主
//        getUsr.put("OwState",getSigningWechatOwner.get("OwState"));
        return getUsr;
    }

    /**
     * 根据TenId修改用户的名字或者图片
     *
     * @param params
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public JsonResult updateUsrNameorUimg(Map<String, Object> params) {
        JsonResult result = new JsonResult();
        log.info("params=====>" + params);
        /**
         * 加锁操作
         */
        lock.lock();
        try {
            if (wxdao.updateUsrNameorUimg(params) > 0) {

                result.putSuccess("操作成功");

            } else {

                result.putFailed("操作失败");
            }

        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//事物回滚
            result.putFailed("服务器放忙...");
        } finally {
            lock.unlock();
        }

        return result;
    }

    /**
     * 用户修改手机号
     *
     * @param params
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public JsonResult updateTenPhoneByTenId(Map<String, Object> params) {
        JsonResult result = new JsonResult();
        /**
         * 加锁操作
         */
        lock.lock();
        try {
            log.info("TenPhone>>>=" + params.get("TenPhone"));
            params.put("phone", params.get("TenPhone"));
            log.info("phone>>>=" + params.get("phone"));
            if (wxdao.getCountPhone(params) > 0) {//用于后面的查询
                result.putFailed("该手机号码已绑定用户");
            } else {
                if ("".equals(params.get("TenPhone").toString()) || params.get("TenPhone").toString() == null) {
                    result.putFailed("请输入手机号");
                } else {

                    if (wxdao.updateTenPhoneByTenId(params) > 0) {
                        result.putSuccess("操作成功");
                    } else {
                        result.putFailed("操作失败");
                    }
                }
            }
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//事物回滚
            result.putFailed("服务器繁忙...");
        } finally {
            lock.unlock();
        }
        return result;
    }

    /**
     * 成为业主
     *
     * @param params
     * @return
     */

    @Transactional(rollbackFor = Exception.class)
    @Override
    public JsonResult AstheOwner(Map<String, Object> params) {
        JsonResult result = new JsonResult();
        /**
         * 加锁操作
         */
        lock.lock();
        try {
            params.put("openid", params.get("uopid"));
            JsonResult jsonResult = marketFeignClient.AddCommunity(params);
            log.info("jsonResult>>>" + jsonResult);
            String code = jsonResult.get("errorCode").toString();
            log.info("code>>>" + code);
            if (code.equals("0")) {
                if (wxdao.updatetenantUsrType(params) > 0) {
                    result.putSuccess("操作成功");
                } else {
                    result.putFailed("操作失败");
                }
            } else {
                result.putFailed("操作失败");
            }
        } catch (Exception e) {
            log.error("E------->" + e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//事物回滚
            result.putFailed("服务器繁忙...");
        } finally {
            lock.unlock();
        }
        return result;
    }

    @Override
    public Map<String, Object> getTenOpenId(Map<String, Object> params) {
        return wxdao.getTenOpenId(params);
    }

}
